package com.yanqu.road.entity.kuang.battle;

import com.yanqu.road.entity.DataObject;
import com.yanqu.road.entity.DataStatus;
import com.yanqu.road.entity.FieldTypeAnnotation;
import com.yanqu.road.entity.enums.kuang.eKuangAttributeType;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;

@FieldTypeAnnotation(tableName = "t_c_kuang_battle_user_data")
public class CrossKuangBattleUserData extends DataObject {

    @FieldTypeAnnotation(desc = "周次id", select = true, update = true)
    private int weekId;

    @FieldTypeAnnotation(desc = "分组id", select = true, update = true)
    private int groupId;

    @FieldTypeAnnotation(desc = "玩家ID", select = true, update = true)
    private long userId;

    @FieldTypeAnnotation(desc = "服务器id")
    private long serverId;

    @FieldTypeAnnotation(desc = "玩家属性")
    private Map<eKuangAttributeType, Long> attributeMap = new HashMap<>();

    @FieldTypeAnnotation(desc = "玩家buff")
    private List<CrossKuangBattleUserBuff> buffList = new ArrayList<>();

    @FieldTypeAnnotation(desc = "玩家技能")
    private List<CrossKuangBattleUserSkill> skillList = new ArrayList<>();

    @FieldTypeAnnotation(desc = "宗门id")
    private int campId;

    @FieldTypeAnnotation(desc = "所在地点")
    private int placeId;

    @FieldTypeAnnotation(desc = "位置信息")
    private CrossKuangBattlePosition position = new CrossKuangBattlePosition();


    @FieldTypeAnnotation(desc = "可传送的时间")
    private long transferTime;

    @FieldTypeAnnotation(desc = "最后一次攻击时间")
    private long attackTime;

    @FieldTypeAnnotation(desc = "最后一次被攻击时间")
    private long attackedTime;

    @FieldTypeAnnotation(desc = "复活时间")
    private long reviveTime;

    @FieldTypeAnnotation(desc = "复活了多少次")
    private int reviveCnt;

    @FieldTypeAnnotation(desc = "属性更新时间")
    private long updatePropertyTime;

    @FieldTypeAnnotation(desc = "本条命战绩")
    private CrossKuangBattleRecord battleRecord = new CrossKuangBattleRecord();

    @FieldTypeAnnotation(desc = "总战绩")
    private Map<Integer, CrossKuangBattleRecord> totalBattleRecordMap = new ConcurrentHashMap<>();

    @FieldTypeAnnotation(desc = "个人击杀总战绩")
    private Map<Integer, Long> attackScoreMap = new ConcurrentHashMap<>();

    @FieldTypeAnnotation(desc = "个人占点总战绩")
    private Map<Integer, Long> seizeScoreMap = new ConcurrentHashMap<>();

    @FieldTypeAnnotation(desc = "个人战绩更新时间")
    private long updateScoreTime;

    @FieldTypeAnnotation(desc = "房间心跳时间")
    private long lastPingPlaceTime;

    @FieldTypeAnnotation(desc = "个人战绩榜单是否领奖")
    private boolean personRankReward;

    @FieldTypeAnnotation(desc = "宗门积分榜单是否领奖")
    private boolean groupRankReward;

    @FieldTypeAnnotation(desc = "是否进入过战斗")
    private boolean enterBattle;

    public CrossKuangBattleUserData() {

    }

    public int getWeekId() {
        return weekId;
    }
    public void setWeekId(int weekId) {
        if (this.weekId != weekId) {
            this.weekId = weekId;
            setOp(DataStatus.Update);
        }
    }

    public int getGroupId() {
        return groupId;
    }
    public void setGroupId(int groupId) {
        if (this.groupId != groupId) {
            this.groupId = groupId;
            setOp(DataStatus.Update);
        }
    }

    public long getUserId() {
        return userId;
    }
    public void setUserId(long userId) {
        if (this.userId != userId) {
            this.userId = userId;
            setOp(DataStatus.Update);
        }
    }

    public long getServerId() {
        return serverId;
    }

    public void setServerId(long serverId) {
        if (this.serverId != serverId) {
            this.serverId = serverId;
            setOp(DataStatus.Update);
        }
    }

    public Map<eKuangAttributeType, Long> getAttributeMap() {
        return attributeMap;
    }
    public void setAttributeMap(Map<eKuangAttributeType, Long> attributeMap) {
        if (null == attributeMap){
            return;
        }
        if (this.attributeMap == null || !this.attributeMap.equals(attributeMap)) {
            this.attributeMap = attributeMap;
            setOp(DataStatus.Update);
        }
    }

    /**
     * 战斗过程中都调用这个属性（含buff）
     */
    public Map<eKuangAttributeType, Long> getActualAttributeMap() {
        checkBuff();
        Map<eKuangAttributeType, Long> map = new ConcurrentHashMap<>(attributeMap);
        for (CrossKuangBattleUserBuff userBuff : getBuffList()) {
            // 攻击是加成当前攻击的千分比
            if (userBuff.getType() == eKuangAttributeType.AttributeEnum_Attack) {
                long addAttack = BigDecimal.valueOf(attributeMap.getOrDefault(eKuangAttributeType.AttributeEnum_Attack, 0L)).multiply(BigDecimal.valueOf(userBuff.getValue()).divide(BigDecimal.valueOf(1000), 8, RoundingMode.UP)).setScale(0, RoundingMode.UP).longValue();
                map.put(eKuangAttributeType.AttributeEnum_Attack, map.getOrDefault(eKuangAttributeType.AttributeEnum_Attack, 0L) + addAttack);
            } else if (userBuff.getType() == eKuangAttributeType.AttributeEnum_Hp) {
                long addHp = BigDecimal.valueOf(attributeMap.getOrDefault(eKuangAttributeType.AttributeEnum_Hp, 0L)).multiply(BigDecimal.valueOf(userBuff.getValue()).divide(BigDecimal.valueOf(1000), 8, RoundingMode.UP)).setScale(0, RoundingMode.UP).longValue();
                map.put(eKuangAttributeType.AttributeEnum_Hp, map.getOrDefault(eKuangAttributeType.AttributeEnum_Hp, 0L) + addHp);
            } else {
                // 其他类型直接加成千分比
                map.put(userBuff.getType(), map.getOrDefault(userBuff.getType(), 0L) + userBuff.getValue());
            }
        }
        return map;
    }

    /**
     * 移除过期buff
     */
    public void checkBuff() {
        long nowTime = System.currentTimeMillis();
        synchronized (buffList) {
            Iterator<CrossKuangBattleUserBuff> iterator = buffList.iterator();
            while (iterator.hasNext()) {
                CrossKuangBattleUserBuff next = iterator.next();
                if (nowTime >= next.getExpireTime()) {
                    if (next.getType() == eKuangAttributeType.AttributeEnum_Hp) {
                        // 血量buff到期需要检测下血量
                        setCurHp(Math.min(getCurHp(), getMaxHp()));
                    }
                    iterator.remove();
                }
            }
        }
        setOp(DataStatus.Update);
    }

    /**
     * 添加buff
     */
    public void addBuff(CrossKuangBattleUserBuff userBuff) {
        synchronized (buffList) {
            buffList.add(userBuff);
        }
        if (userBuff.getType() == eKuangAttributeType.AttributeEnum_Hp) {
            // 需要算下当前血量的加成
            long addHp = BigDecimal.valueOf(attributeMap.getOrDefault(eKuangAttributeType.AttributeEnum_Hp, 0L)).multiply(BigDecimal.valueOf(userBuff.getValue()).divide(BigDecimal.valueOf(1000), 8, RoundingMode.UP)).setScale(0, RoundingMode.UP).longValue();
            // 增加当前血量
            offsetHp(addHp);
        }
    }

    public List<CrossKuangBattleUserBuff> getBuffList() {
        return new ArrayList<>(buffList);
    }

    public void setBuffList(List<CrossKuangBattleUserBuff> buffList) {
        if (buffList == null) {
            return;
        }
        this.buffList = buffList;
        setOp(DataStatus.Update);
    }

    public int getCampId() {
        return campId;
    }
    public void setCampId(int campId) {
        if (this.campId != campId) {
            this.campId = campId;
            setOp(DataStatus.Update);
        }
    }

    public int getPlaceId() {
        return placeId;
    }
    public void setPlaceId(int placeId) {
        if (this.placeId != placeId) {
            this.placeId = placeId;
            setOp(DataStatus.Update);
        }
    }

    public CrossKuangBattlePosition getPosition() {
        return position;
    }
    public void setPosition(CrossKuangBattlePosition position) {
        if (null == position){
            return;
        }
        if (this.position == null || !this.position.equals(position)) {
            this.position = position;
            setOp(DataStatus.Update);
        }
    }

    public long getTransferTime() {
        return transferTime;
    }
    public void setTransferTime(long transferTime) {
        if (this.transferTime != transferTime) {
            this.transferTime = transferTime;
            setOp(DataStatus.Update);
        }
    }

    public long getAttackTime() {
        return attackTime;
    }
    public void setAttackTime(long attackTime) {
        if (this.attackTime != attackTime) {
            this.attackTime = attackTime;
            setOp(DataStatus.Update);
        }
    }

    public long getAttackedTime() {
        return attackedTime;
    }
    public void setAttackedTime(long attackedTime) {
        if (this.attackedTime != attackedTime) {
            this.attackedTime = attackedTime;
            setOp(DataStatus.Update);
        }
    }

    public long getReviveTime() {
        return reviveTime;
    }
    public void setReviveTime(long reviveTime) {
        if (this.reviveTime != reviveTime) {
            this.reviveTime = reviveTime;
            setOp(DataStatus.Update);
        }
    }

    public int getReviveCnt() {
        return reviveCnt;
    }
    public void setReviveCnt(int reviveCnt) {
        if (this.reviveCnt != reviveCnt) {
            this.reviveCnt = reviveCnt;
            setOp(DataStatus.Update);
        }
    }

    public long getUpdatePropertyTime() {
        return updatePropertyTime;
    }
    public void setUpdatePropertyTime(long updatePropertyTime) {
        if (this.updatePropertyTime != updatePropertyTime) {
            this.updatePropertyTime = updatePropertyTime;
            setOp(DataStatus.Update);
        }
    }

    public CrossKuangBattleRecord getBattleRecord() {
        return battleRecord;
    }
    public void setBattleRecord(CrossKuangBattleRecord battleRecord) {
        if (null == battleRecord){
            return;
        }
        if (this.battleRecord == null || !this.battleRecord.equals(battleRecord)) {
            this.battleRecord = battleRecord;
            setOp(DataStatus.Update);
        }
    }

    public Map<Integer, CrossKuangBattleRecord> getTotalBattleRecordMap() {
        return totalBattleRecordMap;
    }

    public CrossKuangBattleRecord getRoundBattleRecord(int round) {
        if (!totalBattleRecordMap.containsKey(round)) {
            totalBattleRecordMap.put(round, new CrossKuangBattleRecord());
            setOp(DataStatus.Update);
        }
        return totalBattleRecordMap.get(round);
    }

    public void setTotalBattleRecordMap(Map<Integer, CrossKuangBattleRecord> totalBattleRecordMap) {
        if (totalBattleRecordMap == null) {
            return;
        }
        this.totalBattleRecordMap = totalBattleRecordMap;
        setOp(DataStatus.Update);
    }

    public Map<Integer, Long> getAttackScoreMap() {
        return attackScoreMap;
    }

    public void setAttackScoreMap(Map<Integer, Long> attackScoreMap) {
        if (attackScoreMap == null) {
            return;
        }
        this.attackScoreMap = attackScoreMap;
        setOp(DataStatus.Update);
    }

    public Map<Integer, Long> getSeizeScoreMap() {
        return seizeScoreMap;
    }

    public void setSeizeScoreMap(Map<Integer, Long> seizeScoreMap) {
        if (seizeScoreMap == null) {
            return;
        }
        this.seizeScoreMap = seizeScoreMap;
        setOp(DataStatus.Update);
    }

    public long getUpdateScoreTime() {
        return updateScoreTime;
    }

    public void setUpdateScoreTime(long updateScoreTime) {
        if (this.updateScoreTime != updateScoreTime) {
            this.updateScoreTime = updateScoreTime;
            setOp(DataStatus.Update);
        }

    }

    public long getLastPingPlaceTime() {
        return lastPingPlaceTime;
    }
    public void setLastPingPlaceTime(long lastPingPlaceTime) {
        if (this.lastPingPlaceTime != lastPingPlaceTime) {
            this.lastPingPlaceTime = lastPingPlaceTime;
            setOp(DataStatus.Update);
        }
    }

    public CrossKuangBattleUserSkill getSkill(int type) {
        return getSkill(type, 0);
    }

    public CrossKuangBattleUserSkill getSkill(int type, int littleType) {
        for (CrossKuangBattleUserSkill userSkill : skillList) {
            if (userSkill.getType() == type && userSkill.getLittleType() == littleType) {
                return userSkill;
            }
        }
        return null;
    }

    public List<CrossKuangBattleUserSkill> getSkillList() {
        return skillList;
    }

    public void setSkillList(List<CrossKuangBattleUserSkill> skillList) {
        if (skillList == null) {
            return;
        }
        this.skillList = skillList;
        setOp(DataStatus.Update);
    }

    /**
     * 获取用户状态  0 正常，1死亡
     */
    public int getUserState() {
        return attributeMap.getOrDefault(eKuangAttributeType.AttributeEnum_CurHp, 0L) <= 0 || reviveTime > System.currentTimeMillis() ? 1 : 0;
    }

    /**
     * 血量变化
     * 血量范围 [0,maxHp]
     *
     * @return 血量变化值
     */
    public long offsetHp(long offsetHp) {
        long beforeHp = getCurHp();
        setCurHp(Math.min(getMaxHp(), Math.max(0, beforeHp + offsetHp)));
        return Math.abs(getCurHp() - beforeHp);
    }

    public long getCurHp() {
        return attributeMap.getOrDefault(eKuangAttributeType.AttributeEnum_CurHp, 0L);
    }

    public void setCurHp(long curHp) {
        attributeMap.put(eKuangAttributeType.AttributeEnum_CurHp, curHp);
    }

    public long getMaxHp() {
        long nowTime = System.currentTimeMillis();
        long totalAddition = 0;
        // 检测当前buff
        synchronized (buffList) {
            for (CrossKuangBattleUserBuff userBuff : buffList) {
                if (userBuff.getType() == eKuangAttributeType.AttributeEnum_Hp && userBuff.getExpireTime() > nowTime) {
                    // 生效中的血量buff
                    totalAddition += userBuff.getValue();
                }
            }
        }
        return BigDecimal.valueOf(attributeMap.getOrDefault(eKuangAttributeType.AttributeEnum_Hp, 0L)).multiply(BigDecimal.valueOf(1000 + totalAddition)).divide(BigDecimal.valueOf(1000), 0, RoundingMode.UP).longValue();
    }

    public long calcTotalScore() {
        long totalScore = 0;
        for (Long score : attackScoreMap.values()) {
            totalScore += score;
        }
        for (Long score : seizeScoreMap.values()) {
            totalScore += score;
        }
        return totalScore;
    }

    public long getRoundTotalScore(int roundDay) {
        return attackScoreMap.getOrDefault(roundDay, 0L) + seizeScoreMap.getOrDefault(roundDay, 0L);
    }

    public boolean isPersonRankReward() {
        return personRankReward;
    }

    public void setPersonRankReward(boolean personRankReward) {
        if (this.personRankReward != personRankReward) {
            this.personRankReward = personRankReward;
            setOp(DataStatus.Update);
        }
    }

    public boolean isGroupRankReward() {
        return groupRankReward;
    }

    public void setGroupRankReward(boolean groupRankReward) {
        if (this.groupRankReward != groupRankReward) {
            this.groupRankReward = groupRankReward;
            setOp(DataStatus.Update);
        }
    }

    public boolean isEnterBattle() {
        return enterBattle;
    }

    public void setEnterBattle(boolean enterBattle) {
        if (this.enterBattle != enterBattle) {
            this.enterBattle = enterBattle;
            setOp(DataStatus.Update);
        }
    }
}
